package com.yjha.ai.demos.web.service;

import com.google.gson.Gson;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import com.yjha.ai.demos.web.entity.Recording;
import com.yjha.ai.demos.web.utils.SQLExecutor;
import com.yjha.ai.demos.web.value.APIValue;
import com.yjha.ai.demos.web.value.DataHistogram;
import com.yjha.ai.demos.web.value.Datasets;
import jakarta.annotation.Resource;
import lombok.RequiredArgsConstructor;
import org.json.JSONArray;
import org.json.JSONObject;
import org.springframework.ai.chat.messages.Message;
import org.springframework.ai.chat.messages.UserMessage;
import org.springframework.ai.chat.model.ChatResponse;
import org.springframework.ai.chat.prompt.Prompt;
import org.springframework.ai.chat.prompt.SystemPromptTemplate;
import org.springframework.ai.zhipuai.ZhiPuAiChatModel;
import org.springframework.stereotype.Service;

import java.sql.*;
import java.util.*;

@Service
public class DBChatService {

    @Resource
    private RecordingService recordingService;

    @Resource
    private ZhiPuAiChatModel chatModel;

    private final static String SYSTEM_PROMPT = """
                你是一个专业的学生画像分析师，首先需要获取指定学生的所有相关信息。请严格按照以下提示进行学生信息获取。
                要求：
                请根据用户选择的数据库和该库的部分可用表结构定义来回答用户问题.
                数据库名：
                {dbName}
                表结构定义：
                {dbInFo}
                数据展示方式：
                1，histogram：柱形图使用垂直列来显示类别之间的数值比较，并且列数不应太大（如果列太多，则轴的标签可能显示为不完整）。
                2，条形图与柱形图相似，但是条形图的数量可能相对较大。
                3，折线图用于显示连续时间间隔或时间跨度内的数据变化。它的特点是随着时间或类别的变化而反映事物的趋势。
                约束：
                1. 请根据用户问题理解用户意图，使用给出表结构定义创建一个语法正确的 mysql sql，如果不需要sql，则直接回答用户问题。
                3. 只能使用表结构信息中提供的表来生成 sql，如果无法根据提供的表结构中生成 sql ，请说：“提供的表结构信息不足以生成 sql 查询。” 禁止随意捏造信息。
                4. 请注意生成SQL时不要弄错表和列的关系。
                5. 请检查SQL的正确性，并保证正确的情况下优化查询性能。
                7.如果是hive sql,则语句后面不要加分号‘;’.
                8.如果是hive sql,则不要给字段取中文别名.
                9.严格按照所提供的表结构信息，以及表信息获取学生相关信息,确保给出的sql语句能够在该表结构中执行。
                10.根据sql语句判断数据应该已怎样的形式可视化展示， 将结果做为display_type的value值。
                用户问题:
                {message}
                请一步步思考并按照以下JSON格式回复：
                       '''{{"thoughts": "thoughts summary to say to user","sql": "You can have multiple SQL statements, and if there are more than one, separate them with English semicolons" ,"display_type": "Data display method"}}'''
                确保返回正确的json并且可以被Python json.loads方法解析.json.
                只输出单纯的可直接执行的json，不需要加任何解释。
            """;
    private final static String SYSTEM_PROMPT2 = """
                你是一个根据用户问题和返回结果来总结最终结果的专家。
                用户问题：{userMessage}
                结果回答：{data}
                要求：
                    1，总结必须简洁，明了，不要啰里啰唆。
             """;

    public Map<String , Object> execute(APIValue apiValue){

        Map<String, Object> stringObjectHashMap = new HashMap<>();

        String dbInFo = getDBInFo(apiValue);

        Map<String , Object> map = new HashMap<>();
        map.put("dbName",apiValue.getDbName());
        map.put("dbInFo", dbInFo);
        map.put("message",apiValue.getMessage());
        // 使用Spring AI 提供的模板方式构建SystemMessage对象
        Message systemMessage = new SystemPromptTemplate(SYSTEM_PROMPT).createMessage(map);

        // 构建UserMessage对象
        UserMessage userMessage = new UserMessage(apiValue.getMessage());
        ChatResponse call = chatModel.call(new Prompt(List.of(systemMessage, userMessage)));

        System.out.println(call.getResult().getOutput().getContent());

        JsonObject jsonObject = parsingEthan(call.getResult().getOutput().getContent());

        return disData(jsonObject , apiValue);

    }

    private  Map<String, Object> disData(JsonObject jsonObject , APIValue apiValue){
        Map<String, Object> stringObjectHashMap = new HashMap<>();
        apiValue.setSql(jsonObject.get("sql").getAsString());

        JSONObject js = SQLExecutor.executeSQL(apiValue);

        System.out.println(js);

        String displayType = jsonObject.get("display_type").getAsString();


        String dateByDisplayType = getDateByDisplayType(displayType, js.toString());

        stringObjectHashMap.put("data",dateByDisplayType);

        if(dateByDisplayType == null){
            stringObjectHashMap.put("message","我是一个智能数据分析助手，请告诉我系统相关问题，我会尽我最大的能力回答你。");
        }else{
            if (dateByDisplayType.length() <= 2000) {
                Map<String , Object> map = new HashMap<>();
                map.put("userMessage",apiValue.getMessage());
                map.put("data",dateByDisplayType);
                Message systemMessage = new SystemPromptTemplate(SYSTEM_PROMPT2).createMessage(map);
                UserMessage userMessage = new UserMessage("帮我总结一下以上问答，尽量简洁，明了");
                System.out.println("问题："+systemMessage);
                ChatResponse call = chatModel.call(new Prompt(List.of(systemMessage,userMessage)));
                stringObjectHashMap.put("message",call.getResult().getOutput().getContent());
            }else{
                stringObjectHashMap.put("message","好的，已帮你展示出数据了");
            }
        }

        Recording recording = new Recording();
        recording.setUserMessage(apiValue.getMessage());
        recording.setSysMessage((String) stringObjectHashMap.get("message"));
        recording.setData(dateByDisplayType);
        recording.setDisplayType(jsonObject.get("display_type").getAsString());
        recordingService.save(recording);
        stringObjectHashMap.put("recording",recording);
        stringObjectHashMap.put("display_type",jsonObject.get("display_type").getAsString());

        return stringObjectHashMap;
    }

    public static void main(String[] args) {
        System.out.println(getDateByDisplayType("histogram", "{\"results\":[{\"student_count\":554,\"blcollege\":\"护理学院\"},{\"student_count\":581,\"blcollege\":\"艺术学院\"},{\"student_count\":2115,\"blcollege\":\"资源环境学院\"},{\"student_count\":1276,\"blcollege\":\"物理科学与技术学院\"},{\"student_count\":1390,\"blcollege\":\"核科学与技术学院\"},{\"student_count\":974,\"blcollege\":\"大气科学学院\"},{\"student_count\":6,\"blcollege\":\"党委统战部\"},{\"student_count\":102,\"blcollege\":\"图书馆\"},{\"student_count\":22,\"blcollege\":\"资产处\"},{\"student_count\":2297,\"blcollege\":\"管理学院\"},{\"student_count\":766,\"blcollege\":\"生态学院\"},{\"student_count\":1031,\"blcollege\":\"生命科学学院\"},{\"student_count\":440,\"blcollege\":\"哲学社会学院\"},{\"student_count\":161,\"blcollege\":\"基础教育管理中心\"},{\"student_count\":578,\"blcollege\":\"地质科学与矿产资源学院\"},{\"student_count\":92,\"blcollege\":\"网络安全与信息化办公室\"},{\"student_count\":1119,\"blcollege\":\"草地农业科技学院\"},{\"student_count\":936,\"blcollege\":\"土木工程与力学学院\"},{\"student_count\":3015,\"blcollege\":\"第二临床医学院\"},{\"student_count\":27,\"blcollege\":\"科学技术发展研究院\"},{\"student_count\":698,\"blcollege\":\"口腔医学院\"},{\"student_count\":27,\"blcollege\":\"教务处\"},{\"student_count\":23,\"blcollege\":\"研究生院\"},{\"student_count\":66,\"blcollege\":\"出版社\"},{\"student_count\":574,\"blcollege\":\"外国语学院\"},{\"student_count\":890,\"blcollege\":\"公共卫生学院\"},{\"student_count\":8,\"blcollege\":\"学科建设与发展规划处（\\u201c双一流\\u201d建设办公室）\"},{\"student_count\":362,\"blcollege\":\"后勤保障部\"},{\"student_count\":1964,\"blcollege\":\"化学化工学院\"},{\"student_count\":37,\"blcollege\":\"学校办公室、政策研究室\"},{\"student_count\":77,\"blcollege\":\"网络与继续教育学院\"},{\"student_count\":20,\"blcollege\":\"党委教师工作部、人力资源部\"},{\"student_count\":81,\"blcollege\":\"高等教育研究院\"},{\"student_count\":91,\"blcollege\":\"保卫处\"},{\"student_count\":841,\"blcollege\":\"药学院\"},{\"student_count\":630,\"blcollege\":\"材料与能源学院\"},{\"student_count\":16,\"blcollege\":\"档案馆\"},{\"student_count\":970,\"blcollege\":\"数学与统计学院\"},{\"student_count\":76,\"blcollege\":\"体育教研部\"},{\"student_count\":69,\"blcollege\":\"功能有机分子化学国家重点实验室\"},{\"student_count\":3343,\"blcollege\":\"第一临床医学院\"},{\"student_count\":939,\"blcollege\":\"经济学院\"},{\"student_count\":8,\"blcollege\":\"博物馆\"},{\"student_count\":9,\"blcollege\":\"共青团兰州大学委员会\"},{\"student_count\":14,\"blcollege\":\"草地微生物研究中心\"},{\"student_count\":260,\"blcollege\":\"政治与国际关系学院\"},{\"student_count\":6,\"blcollege\":\"党委人才办\"},{\"student_count\":1651,\"blcollege\":\"信息科学与工程学院\"},{\"student_count\":27,\"blcollege\":\"西部生态安全协同创新中心\"},{\"student_count\":1034,\"blcollege\":\"法学院\"},{\"student_count\":64,\"blcollege\":\"校医院\"},{\"student_count\":44,\"blcollege\":\"财务处、预算评审中心\"},{\"student_count\":14,\"blcollege\":\"社会科学处\"},{\"student_count\":755,\"blcollege\":\"历史文化学院\"},{\"student_count\":162,\"blcollege\":\"国际文化交流学院\"},{\"student_count\":4,\"blcollege\":\"采购管理办公室\"},{\"student_count\":519,\"blcollege\":\"基础医学院\"},{\"student_count\":14,\"blcollege\":\"党委组织部、党校\"},{\"student_count\":83,\"blcollege\":\"动物医学与生物安全学院\"},{\"student_count\":18,\"blcollege\":\"实验室与设备管理处\"},{\"student_count\":22,\"blcollege\":\"大学科技园管理办公室\"},{\"student_count\":84,\"blcollege\":\"校友工作办公室\"},{\"student_count\":14,\"blcollege\":\"国际合作与交流处（港澳台事务办公室、孔子学院办公室）\"},{\"student_count\":621,\"blcollege\":\"马克思主义学院\"},{\"student_count\":63,\"blcollege\":\"资产经营有限公司\"},{\"student_count\":38,\"blcollege\":\"学生处、招生办公室\"},{\"student_count\":20,\"blcollege\":\"医学部\"},{\"student_count\":10,\"blcollege\":\"兰州大学泛第三极环境中心\"},{\"student_count\":12,\"blcollege\":\"工会\"},{\"student_count\":4,\"blcollege\":\"机关党委\"},{\"student_count\":4,\"blcollege\":\"\\u201c一带一路\\u201d研究中心\"},{\"student_count\":2,\"blcollege\":\"兰州大学黄河流域绿色发展研究院\"},{\"student_count\":4,\"blcollege\":\"兰州大学绿色金融研究院\"},{\"student_count\":10,\"blcollege\":\"学校纪检监察机构（纪委、监察专员办公室）\"},{\"student_count\":5,\"blcollege\":\"榆中校区综合办公室\"},{\"student_count\":81,\"blcollege\":\"其他部门\"},{\"student_count\":2,\"blcollege\":\"图书馆及直属单位党委\"},{\"student_count\":4,\"blcollege\":\"兰州大学青藏高原人文环境研究中心\"},{\"student_count\":10,\"blcollege\":\"审计处\"},{\"student_count\":491,\"blcollege\":\"新闻与传播学院\"},{\"student_count\":721,\"blcollege\":\"文学院\"},{\"student_count\":4,\"blcollege\":\"兰州大学电镜中心\"},{\"student_count\":2,\"blcollege\":\"生态学创新研究院\"},{\"student_count\":6,\"blcollege\":\"国家核产业研究院\"},{\"student_count\":9,\"blcollege\":\"兰州大学稀有同位素前沿科学中心\"},{\"student_count\":7,\"blcollege\":\"离退休工作处\"},{\"student_count\":26,\"blcollege\":\"基本建设处\"},{\"student_count\":6,\"blcollege\":\"县域经济发展研究院（乡村振兴战略研究院）\"},{\"student_count\":6,\"blcollege\":\"党委巡视办公室\"},{\"student_count\":31,\"blcollege\":\"萃英学院\"},{\"student_count\":21,\"blcollege\":\"党委宣传部（融媒体中心）\"},{\"student_count\":17,\"blcollege\":\"兰州大学第一医院\"},{\"student_count\":17,\"blcollege\":\"兰州大学第二医院\"},{\"student_count\":1,\"blcollege\":\"兰州大学幼儿园\"},{\"student_count\":1},{\"student_count\":86,\"blcollege\":\"威尔士学院\"},{\"student_count\":36,\"blcollege\":\"兰州大学附属学校\"},{\"student_count\":1,\"blcollege\":\"劳动服务公司\"},{\"student_count\":1,\"blcollege\":\"兰州大学青藏高原人文环境研究院\"}]}"));
    }

    private static String getDateByDisplayType(String displayType , String json){

        JSONObject jsonObject = new JSONObject(json);

        if(displayType.equals("histogram")) { //如果是柱状图则处理为柱状图数据
            // 解析JSON数组
            JSONArray jsonArray = jsonObject.getJSONArray("results");

            // 创建ArrayList来存储labels和datasets
            List<String> labels = new ArrayList<>();
            List<Integer> datasets = new ArrayList<>();


            // 遍历JSON数组并填充ArrayList
            for (int i = 0; i < jsonArray.length(); i++) {
                JSONObject jsonObj = jsonArray.getJSONObject(i);

                // 获取JSONObject中的所有键
                Set<String> keys = jsonObj.keySet();

                // 遍历所有键
                for (String key : keys) {
                    // 根据键的类型进行相应的处理
                    if (jsonObj.get(key) instanceof String) {
                        labels.add("\""+jsonObj.getString(key)+"\"");
//                        labels.add(jsonObj.getString(key));
                    } else if (jsonObj.get(key) instanceof Integer) {
                        datasets.add(jsonObj.getInt(key));
                    }
                    // 如果需要处理其他类型的数据，可以在这里添加更多的条件判断
                }

            }
            List<Datasets> datasets2 = new ArrayList<>();
            Datasets datasets1 = new Datasets();
            datasets1.setData(datasets);
            datasets1.setLabel("数量");
            datasets1.setBackgroundColor(Arrays.asList("\""+"rgba(255, 99, 132, 0.2)"+"\"","\""+"rgba(54, 162, 235, 0.2)"+"\""));
            datasets1.setBorderColor(Arrays.asList("\""+"rgba(255, 99, 132, 1)"+"\"","\""+"rgba(54, 162, 235, 1)"+"\""));
            datasets1.setBorderWidth(1);
            datasets2.add(datasets1);
            DataHistogram dataHistogram = new DataHistogram(labels,datasets2);

            return dataHistogram.toString();

        }else if(displayType.equals("table")) {
            return jsonObject.toString();
        }else if(displayType.equals("text")){
            return jsonObject.toString();
        }

        return null;
    }

    public String getDBInFo(APIValue apiValue){
        String connectionUrl = "jdbc:mysql://" + apiValue.getIp() + ":" + apiValue.getPort() + "/" + apiValue.getDbName() + "?useUnicode=true&characterEncoding=utf8";

        List<String> output = new ArrayList<>();

        try (Connection connection = DriverManager.getConnection(connectionUrl, apiValue.getAccount(), apiValue.getPassword())) {
            String sql = "SELECT TABLE_NAME, COLUMN_NAME, COLUMN_TYPE, COLUMN_COMMENT FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = ? ORDER BY TABLE_NAME, ORDINAL_POSITION";

            try (PreparedStatement preparedStatement = connection.prepareStatement(sql)) {
                preparedStatement.setString(1, apiValue.getDbName());

                ResultSet resultSet = preparedStatement.executeQuery();
                Map<String, List<String>> formattedResults = new HashMap<>();

                while (resultSet.next()) {
                    String tableName = resultSet.getString("TABLE_NAME");
                    String columnName = resultSet.getString("COLUMN_NAME");
                    String columnComment = resultSet.getString("COLUMN_COMMENT");
                    String columnEntry = columnComment != null && !columnComment.isEmpty() ? columnName + " (" + columnComment + ")" : columnName;

                    formattedResults.computeIfAbsent(tableName, k -> new ArrayList<>()).add(columnEntry);
                }
                for (Map.Entry<String, List<String>> entry : formattedResults.entrySet()) {
                    String formattedTable = entry.getKey() + "(" + String.join(", ", entry.getValue()) + ")";
                    output.add(formattedTable);
                }

                return output.toString();

            } catch (SQLException ex) {
                System.out.println("SQL Exception: " + ex.getMessage());
            }
        } catch (SQLException ex) {
            System.out.println("Connection failure: " + ex.getMessage());
        }

        return "表结构未定义";
    }

    public JsonObject parsingEthan(String jsonString){
        // 找到第一个左大括号的位置
        int startIndex = jsonString.indexOf('{');

        // 找到最后一个右大括号的位置
        int endIndex = jsonString.lastIndexOf('}');

        if (startIndex != -1 && endIndex != -1 && endIndex > startIndex) {
            // 截取包含 JSON 数据的部分
            String jsonPart = jsonString.substring(startIndex, endIndex + 1);

            // 输出截取的结果
            System.out.println("截取的json字符串："+jsonPart);

            //将字符串转化为json
            Gson gson = new Gson();
            JsonObject jsonObject = JsonParser.parseString(jsonPart).getAsJsonObject();

            return jsonObject;

        } else {
            System.out.println("未找到合适的 JSON 数据段。");
        }
        return null;
    }


    public void executeSql(String sql){
        System.out.println("执行sql语句："+sql);
    }


}
